package io.bwqueen.nettylearn;

import io.netty.buffer.ByteBuf;
import io.netty.channel.ChannelHandler;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelInboundHandlerAdapter;
import io.netty.util.AttributeKey;
import lombok.extern.slf4j.Slf4j;


/**
 * Sharable就是用于告诉netty，我这个Handler是线程安全的，可以被多个channel安全的share
 * 假如你搞了个线程不安全的类，你对它用上了单例，还加个Sharable注解，这时候netty拿你也没办法，只是你的老板可能会有点不开心
 * 参考：<a href="https://blog.csdn.net/cristianoxm/article/details/120483682">...</a>
 * // protected void initChannel(NioSocketChannel ch)
 * // 每次都是new一个新对象，这时候你的xxxChannelHandler加不加Sharable注解都没什么区别
 * //   ch.pipeline().addLast(new XXXChannelHandler());
 * @author bwqueen
 */
@Slf4j
@ChannelHandler.Sharable
public class TcpServerHandler extends ChannelInboundHandlerAdapter {


    /**
     * 每一个channel都有独立的handler、channelHandlerContext、ChannelPipeline、Attribute
     * 所有不需要担心多个channel中的这些对象相互影响
     * 这里使用“content”这个key，记录这个handler中
     */
    private static final AttributeKey<StringBuffer> CONTENT = AttributeKey.valueOf("content");

    /**
     * 文章结束符 over
     */
    private static final String END_KEYWORD = "over";

    @Override
    public void channelRegistered(ChannelHandlerContext ctx) {
        log.info("super.channelRegistered(ctx)");
    }

    @Override
    public void channelUnregistered(ChannelHandlerContext ctx) {
        log.info("super.channelUnregistered(ctx)");
    }

    @Override
    public void channelActive(ChannelHandlerContext ctx) {
        log.info("super.channelActive(ctx) = {}", ctx.toString());
    }

    @Override
    public void channelInactive(ChannelHandlerContext ctx) {
        log.info("super.channelInactive(ctx)");
    }

    @Override
    public void channelRead(ChannelHandlerContext ctx, Object msg) {
        log.info("super.channelRead(ctx, msg)");
        ByteBuf byteBuf = (ByteBuf) msg;
        try {
            StringBuilder contentBuffer = new StringBuilder();
            while (byteBuf.isReadable()) {
                contentBuffer.append((char) byteBuf.readByte());
            }
            // 加入到临时区域
            StringBuffer content = ctx.channel().attr(TcpServerHandler.CONTENT).get();
            if (content == null) {
                content = new StringBuffer();
                ctx.channel().attr(TcpServerHandler.CONTENT).set(content);
            }
            content.append(contentBuffer);
        } finally {
            byteBuf.release();
        }
    }

    @Override
    public void channelReadComplete(ChannelHandlerContext ctx) {
        log.info("super.channelReadComplete(ctx)");
        // 由readComplete方法负责检查数据是否接收完了
        // 检查整个内容中是否有“over”关键字
        StringBuffer content = ctx.channel().attr(TcpServerHandler.CONTENT).get();
        // 如果条件成立说明还没有接收到完整的客户端信息
        if (content != null && content.indexOf(END_KEYWORD) == -1) {
            return;
        }

        // 当接收到信息之后，首先要做的就是清空原来的历史信息
        ctx.channel().attr(TcpServerHandler.CONTENT).set(new StringBuffer());

        // 准备向客户端发送响应
        ByteBuf byteBuf = ctx.alloc().buffer(1024);
        byteBuf.writeBytes("回发响应信息!".getBytes());
        ctx.writeAndFlush(byteBuf);
        // 关闭，正常终止这个通道上下文，就可以关闭通道了
        // （如果不关闭，这个通道的会话将一直存在，只要网络是稳定的，服务器就可以随时通过这个会话向客户端发送信息）
        // 关闭通道意味着TCP将正常断开，其中所有的handler、ChannelHandlerContext、ChannelPipeline、Att-
        // -ribute等信息都将被注销
        ctx.close();
    }

    @Override
    public void userEventTriggered(ChannelHandlerContext ctx, Object evt) {
        log.info("super.ChannelHandlerContext(ctx, evt)");
    }

    @Override
    public void channelWritabilityChanged(ChannelHandlerContext ctx) {
        log.info("super.channelWritabilityChanged(ctx)");
    }

    @Override
    public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) {
        log.info("super.exceptionCaught(ctx, cause)");
    }

    @Override
    public void handlerAdded(ChannelHandlerContext ctx) {
        log.info("super.handlerAdded(ctx)");
    }

    @Override
    public void handlerRemoved(ChannelHandlerContext ctx) {
        log.info("super.handlerRemoved(ctx)");
    }
}
